﻿using System;
using System.Reflection;
using System.Xml;
using System.IO;
using System.Collections.Generic;
using System.Web;

namespace Ecopsy.DataTier
{
    /// <summary>
    /// Static tools of Entity    
    /// </summary>
    public class ReflectionItem
    {
        
        /// <summary>
        /// Create instance
        /// </summary>
        /// <param name="nd"></param>
        /// <returns></returns>
        public static object CreateInstance(XmlNode nd)
        {
            try
            {
                string a = nd.Attributes[SerilizeContext.AssemblyPref].Value;
                string s = nd.Attributes[SerilizeContext.TypePref].Value;
         

                Type InstanceType = MyGetType(a, s);
                object NewObj= null;
                
                if(s.IndexOf ("+")>-1)
                        NewObj = Activator.CreateInstance(InstanceType);                
                    else 
                        NewObj = Activator.CreateInstance(InstanceType, null);                
                
                return NewObj;
            }
            catch (Exception ex)
            {
                throw new Exception(
                    "Не могу создать объект{0}", ex);
            }

        }

        /// <summary>
        /// Инстанцирует объект из строчки
        /// </summary>
        /// <param name="XmlStr"></param>
        /// <returns></returns>
        public static object CreateInstance(string XmlStr )
        {
            XmlDocument d = new XmlDocument();
            try
            {
                TextReader stringReader = new StringReader(XmlStr);
                XmlTextReader r = new XmlTextReader(stringReader);                
                d.Load(r);
                if (null == d.FirstChild) return null;
                return CreateInstance(d.FirstChild);
            }
            finally
            { 
                
            }
        }

        protected static Type MyGetType(string AssemblyName, string TypeName)
        {
                Assembly a = GetAssembly(AssemblyName);
                if (null == a) return null;
                Type t= a.GetType(TypeName);
                return t;
         
        }

       


        /// <summary>
        /// Ищет тип во всех сборках текущего домена
        /// </summary>
        /// <param name="TypeName"></param>
        /// <returns></returns>
        protected static Type MyGetType(string TypeName)
        {
            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())            

            foreach (Module m in a.GetModules())
            {
                foreach (Type t in m.GetTypes())
                {
                    if (t.ToString().Equals(TypeName)) return t;
                }
            }
            return null;

        }

        private static Assembly GetAssembly(string AssemblyName)
        {
            foreach (Assembly item in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (item.ToString().Equals(AssemblyName)) return item;

            }
            return null;
        }

        protected  static bool ImSerisableAtt(PropertyInfo inf)
        {
            if(ImEntityNonSerialized(inf)) return false ;

            if (
                                      
                      inf.PropertyType.Equals(typeof(String)) |
                      inf.PropertyType.Equals(typeof(Decimal)) |
                      inf.PropertyType.Equals(typeof(DateTime)) |
                      inf.PropertyType.Equals(typeof(Boolean)) |
                      inf.PropertyType.Equals(typeof(int)) |
                      inf.PropertyType.Equals(typeof(object))
                      )
                return true;
            else
                return false;
        }
                
        /// <summary>
        /// вернуть список сереизуемых скалярных свойств типа
        /// </summary>
        /// <param name="tp"></param>
        /// <returns></returns>
        protected static List<PropertyInfo> GetSerisableAttProperty(Type tp)
        {
            List<PropertyInfo> res = new List<PropertyInfo>(); 
            foreach (PropertyInfo inf in tp.GetProperties())
            {
                if (ImSerisableAtt(inf)) res.Add(inf);
            }
            return res;

        }

        /// <summary>
        /// возвращает список свойств типа указанного в TypeName, исключая несерилизуемые
        /// 
        /// </summary>
        /// <param name="tp"></param>
        /// <returns></returns>
        protected static List<PropertyInfo> GetSerisablePropertyList(Type ObjectType, string   InterFaceName)
        {
             
            List<PropertyInfo> res = new List<PropertyInfo>();

            foreach (PropertyInfo inf in ObjectType.GetProperties())
            {   
                if (ImEntityNonSerialized(inf)) continue;
                if (ImSupposeInterface(inf.PropertyType, InterFaceName)) res.Add(inf);    
            }

            return res;

        }

        /// <summary>
        /// возвращает список свойств типа указанного в TypeName
        /// Пддерживающих интерфейс (если InterFaceName=string.empty) не учитывается
        /// </summary>
        /// <param name="tp"></param>
        /// <returns></returns>
        protected static List<PropertyInfo> GetPropertyList(Type ObjectType, string InterFaceName,Type Attribute )
        {

            List<PropertyInfo> res = new List<PropertyInfo>();

            foreach (PropertyInfo inf in ObjectType.GetProperties())
            {
                if (ImEntityNonSerialized(inf)) continue;
                if (!inf.IsDefined(Attribute, true)) continue;
                if (InterFaceName == string.Empty) { res.Add(inf); continue; }
                if (ImSupposeInterface(inf.PropertyType, InterFaceName)) res.Add(inf);
            }

            return res;

        }


        /// <summary>
        /// возвращает список свойств типа указанного в TypeName
        /// Пддерживающих интерфейс (если InterFaceName=string.empty) не учитывается
        /// </summary>
        /// <param name="tp"></param>
        /// <returns></returns>
        protected static List<MethodInfo> GetMetodList(Type ObjectType,  Type Attribute)
        {
            List<MethodInfo> res = new List<MethodInfo>();

            foreach (MethodInfo inf in ObjectType.GetMethods() )
            {                
                if (!inf.IsDefined(Attribute, true)) continue;                
                res.Add(inf);
            }

            return res;

        }




        protected static bool ImEntityNonSerialized(PropertyInfo inf)
        {
            return inf.IsDefined(typeof(EntityNonSerializedAttribute), true);
        }

        protected static bool ImIsInterfaceEntity(PropertyInfo inf)
        {
            return inf.IsDefined(typeof(IsInterfaceEntity), true);
        }

        //protected static bool ImReportItem(MemberInfo  inf)
        //{            
        //    return inf.IsDefined(typeof(ImReportItem), true);
        //}

        //protected static bool ImNotReportItem(MemberInfo inf)
        //{
        //    return inf.IsDefined(typeof(ImNotReportItem), true);
        //}

        protected static bool ImSupposeInterface(Type tp, string InterfaceName)
        {
            foreach (Type item in tp.GetInterfaces())
            {
                if (item.ToString().IndexOf(InterfaceName) > -1) return true;
            }
            return false;
        }

    }

}
